package com.demo.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;

@Configuration
@Slf4j
public class RabbitConfig implements RabbitTemplate.ConfirmCallback, RabbitTemplate.ReturnsCallback {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    /**
     * @PostConstruct注解是 """Java中的一个标准注解"""，它用于指定在"""对象创建之后立即执行的方法"""。当使用依赖注入（如Spring框架）或者其他方式创建对象时，@PostConstruct注解可以确保在对象完全初始化之后，执行相应的方法。
     *
     * 使用@PostConstruct注解的方法必须满足以下条件：
     *
     * 1. 方法不能有任何参数。
     * 2. 方法必须是非静态的。
     * 3. 方法不能返回任何值。
     *
     * 当容器实例化一个带有@PostConstruct注解的Bean时，它会在”“”调用构造函数之后，并在依赖注入完成之前"""调用被@PostConstruct注解标记的方法。这样，我们可以在该方法中进行一些初始化操作，比如读取配置文件、建立数据库连接等
     */
    @PostConstruct
    public void initRabbitTemplate(){
        rabbitTemplate.setConfirmCallback(this);
        rabbitTemplate.setReturnsCallback(this);
    }

    @Override
    public void confirm(CorrelationData correlationData, boolean ack, String cause) {
        //消息发送到交换机 成功|失败 都会调用这个方法
        log.info("confirm() 回调函数打印 CorrelationData：{}", correlationData);
        log.info("confirm() 回调函数打印 ack：{}", ack);
        log.info("confirm() 回调函数打印 cause：{}", cause);
    }

    @Override
    public void returnedMessage(ReturnedMessage returned) {
        //发送到队列失败时才会调用这个方法
        log.info("returnedMessage() 回调函数 消息主体：{}", new String(returned.getMessage().getBody()));
        log.info("returnedMessage() 回调函数 应答码：{}", returned.getReplyCode());
        log.info("returnedMessage() 回调函数 描述：{}", returned.getReplyText());
        log.info("returnedMessage() 回调函数 消息使用的交换器 exchange：{}", returned.getExchange());
        log.info("returnedMessage() 回调函数 消息使用的路由键 routingKey：{}", returned.getRoutingKey());
    }
}
